package com.smit.common;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.SystemClock;

import com.smit.adapter.DVBAdapter;
import com.smit.dvb.ci.CIControl;
import com.smit.network.SyncHttpMannager;
import com.smit.utils.LogUtil;
import com.smit.utils.MD5Util;
import com.smit.utils.NetUtil;
import com.smit.utils.StrUtil;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Locale;
import java.util.Random;

/**
 * 鉴权线程
 */
class AuthThread extends Thread {
    private static final String TAG = "AuthThread";
    private boolean bWait = true;
    private boolean bAuthOk = false;
    private String preApik = null;
    private String preDongleId = null;
    private String preDongleType = null;
    private String apik = null;
    private String dongleId = null;
    private String dongleType = null;
    private Object objectWait = new Object();
    private String ethMacAddr;
    private String wifiMacAddr;
    private String randomStr;
    private String snStr;

    private DVBAdapter dvbAdapter;
    private Context context;

    /**
     * 构造函数
     *
     * @param context Android application context
     */
    public AuthThread(Context context) {
        this.context = context;
        setName("AuthThread");
        dvbAdapter = DVBAdapter.getInstance();
    }

    /**
     * 设置等待标志
     *
     * @param flag true 鉴权挂起，false开始鉴权
     */
    public void setWaitFlag(boolean flag) {
        synchronized (objectWait) {
            bWait = flag;
            if (bWait == false) {
                objectWait.notify();
            }
        }

    }

    private boolean bothNetAndDongleOk() {
        return (NetUtil.isNetworkOk(context) && dvbAdapter.getDVBDeviceManager().getDVBDevice().isConnected());
    }

    private void readAuthArgs() {
        LogUtil.trace(TAG, "readAuthArgs: start");
        SharedPreferences pref = context.getSharedPreferences(AppData.PREF_SHARE_NAME, 0);
        preApik = pref.getString(AppData.PREF_APIK, null);
        preDongleId = pref.getString(AppData.PREF_DEVICE_ID, null);
        preDongleType = pref.getString(AppData.PREF_DEVICE_TYPE, null);
        LogUtil.debug(TAG, "readAuthArgs:\r\n" + "preApik = " + preApik + "\r\npreDongleId = " + preDongleId
                + "\r\npreDongleType = " + preDongleType);
        LogUtil.trace(TAG, "readAuthArgs: end");
    }

    private void saveAuthArgs() {
        LogUtil.trace(TAG, "saveAuthArgs: start");
        SharedPreferences pref = context.getSharedPreferences(AppData.PREF_SHARE_NAME, 0);
        Editor editor = pref.edit();
        editor.putString(AppData.PREF_APIK, apik);
        editor.putString(AppData.PREF_DEVICE_ID, dongleId);
        editor.putString(AppData.PREF_DEVICE_TYPE, dongleType);
        LogUtil.info(TAG, "saveAuthArgs:\r\n" + "apik = " + apik + "\r\ndongleId = " + dongleId + "\r\ndongleType = "
                + dongleType);
        editor.apply();
        LogUtil.trace(TAG, "saveAuthArgs: end");
    }

    private void saveDongleParams() {
        LogUtil.trace(TAG, "saveDongleParams: start");
        SharedPreferences pref = context.getSharedPreferences(AppData.PREF_SHARE_NAME, 0);
        Editor editor = pref.edit();
        editor.putString(AppData.PREF_DEVICE_ID, dongleId);
        editor.putString(AppData.PREF_DEVICE_TYPE, dongleType);
        LogUtil.info(TAG, "saveDongleParams:\r\n" + "dongleId = " + dongleId + "\r\ndongleType = " + dongleType);
        editor.apply();
        LogUtil.trace(TAG, "saveDongleParams: end");
    }

    private boolean readDongleInfo() {
        LogUtil.trace(TAG, "readDongleInfo: start");
        while (dvbAdapter.getDVBDeviceManager().getDVBDevice().isConnected()) {
            CIControl ciControl = dvbAdapter.getDVBManager().getCIControl();
            if (ciControl != null && ciControl.getDeviceId() != null) {
                dongleId = ciControl.getDeviceId();
            }
            // dongleId = "123456";
            LogUtil.trace(TAG, "dongleId=" + dongleId);
            if (ciControl != null && ciControl.getDeviceType() != null) {
                dongleType = ciControl.getDeviceType();
            }
            // dongleType = "0d145639";
            LogUtil.trace(TAG, "dongleType=" + dongleType);
            if (StrUtil.isNullOrEmpty(dongleId) == false && StrUtil.isNullOrEmpty(dongleType) == false) {
                //saveDongleParams();
                AuthControl.getInstance().setDongleId(dongleId);
                AuthControl.getInstance().setDongleType(dongleType);
                LogUtil.trace(TAG, "readDongleInfo: end");
                return true;
            } else {
                SystemClock.sleep(100);
                LogUtil.debug(TAG, "Wait for get dongleId and dongleType");
            }
        }
        return false;
    }

    private boolean requestApik() {
        LogUtil.trace(TAG, "requestApik start");
        HashMap<String, String> authArgs = new HashMap<String, String>();
        /*
        String keyString = "smitsmit@smit" + dongleId + dongleType;
        String ac = HMacMD5.getHmacMd5Str(AppData.APIK_KEY_PREFIX, keyString);
        authArgs.put("did", dongleId);
        authArgs.put("dt", dongleType);
        authArgs.put("ac", ac);
        String authUrl = HttpUrl.getUrl(HttpUrl.DEVICE_AUTH);
        */

        authArgs.put("dongleId", dongleId);
        authArgs.put("dongleType", dongleType);
        authArgs.put("cmac", ethMacAddr);
        authArgs.put("wmac", wifiMacAddr);
        authArgs.put("devBrand", AuthControl.getInstance().getHostBrand());
        authArgs.put("devName", AuthControl.getInstance().getHostProductName());
        authArgs.put("devType", AuthControl.getInstance().getHostType());
        authArgs.put("sysVersion", AuthControl.getInstance().getHostAndroidVersion());
        authArgs.put("platVersion", AuthControl.getInstance().getIcastSdkVersion());
        authArgs.put("loginId", AuthControl.getInstance().getAppId());
        authArgs.put("random", getRandomStr());
        authArgs.put("sn", getSecretStr());
        String authUrl = "http://test.ronghe.tv/openplat/webservice/iCastUserRegister.php";
        
        LogUtil.info(TAG, "requestApik authArgs=" + authArgs.toString());
        SyncHttpMannager syncHttp = new SyncHttpMannager();
        JSONObject authResult = syncHttp.doSyncGetJson(authUrl, authArgs);
        if (authResult == null) {
            LogUtil.info(TAG, "requestApik: authResult is null!");
            apik = null;
            return false;
        } else {
            try {
                LogUtil.trace(TAG, "requestApik: authResult=" + authResult.toString());
                if ("T".equalsIgnoreCase(authResult.getString("s"))) {
                    apik = authResult.getString("apik");
                    // apik = authResult.getString("k");
                    if (StrUtil.isNullOrEmpty(apik) == false) {
                        saveAuthArgs();
                        AuthControl.getInstance().setAuthResult(authResult);
                        return true;
                    } else {
                        apik = null;
                        return false;
                    }
                } else if ("F".equals(authResult.getString("s"))) {
                    LogUtil.info(TAG, "error msg:" + authResult.getString("c"));
                    apik = null;
                    AuthControl.getInstance().setApik(apik);
                    AuthControl.getInstance().setAuthStatus(AuthControl.AUTH_FAIL);
                    return false;
                } else {
                    apik = null;
                    return false;
                }
            } catch (JSONException e) {
                apik = null;
                LogUtil.error(TAG, "requestApik: JSONException authResult = " + authResult.toString());
                return false;
            }
        }
    }

    private boolean doAuth() {
        //1. 从本地获取 preDongleId preDongleType preApik
        // 从dvb获取 dongleId dongleType，如果没有，继续，一直等到有值
        // CamUsb.dongleId = dongleId;
        // CamUsb.dongleType = dongleType;
        // 比较，如果相同就返回true,否则继续 2 步

        //2. 判断网络状态，有网进入鉴权，没有就 sleep 1 s
        //3. 失败 sleep 1s ,再去鉴权，直到成功
        //4. 成功 获取 apik ,保存到pref，返回true

        LogUtil.trace(TAG, "doAuth: start");
        // 从 share 中获取 preDongleId preDongleType preApik
        readAuthArgs();
        // 从 DVB 中获取 dongleId dongleType
        boolean ret = readDongleInfo();
        if (ret == true) {
            if (StrUtil.equalAndNotNull(preDongleId, dongleId) == false) {
                saveDongleParams();
            }
        } else {
            return false;
        }
        //获取有线Mac地址
        ethMacAddr = getEthMacAddress();
        AuthControl.getInstance().setEthMacAddr(ethMacAddr);
        //获取无线Mac地址
        wifiMacAddr = getWifiMacAddress();
        AuthControl.getInstance().setWifiMacAddr(wifiMacAddr);

        if (NetUtil.isNetworkOk(context) == false) {
            return false;
        }

        if (StrUtil.equalAndNotNull(preDongleId, dongleId) && StrUtil.equalAndNotNull(preDongleType, dongleType)) {
            apik = preApik;
            if (StrUtil.isNullOrEmpty(apik) == false) {
                LogUtil.trace(TAG, "doAuth: the same dongle,no need auth again");
                LogUtil.trace(TAG, "doAuth: end");
                return true;
            }
            //else
            //{
            //    apik = null;
            //    return false;
            //}
        }
        while (bothNetAndDongleOk()) {
            try {
                boolean request = false;
                request = requestApik();
                if (request == true) {
                    LogUtil.trace(TAG, "doAuth: end");
                    return true;
                } else if (request == false && AuthControl.getInstance().getAuthStatus() == AuthControl.AUTH_FAIL) {
                    return false; // 鉴权过了，但是失败了
                } else {
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                LogUtil.error(TAG, "doAuth InterruptedException");
                return false;
            } catch (Exception e) {
                LogUtil.error(TAG, "doAuth Exception");
                return false;
            }
        }
        return false;
    }

    private String getEthMacAddress() {
        String macSerial = null;
        String macAddr = null;
        String str = "";
        boolean ethflag = isFileExists("/sys/class/net/eth0/address");
        if (ethflag == true) {
            try {
                Process pp = Runtime.getRuntime().exec("cat /sys/class/net/eth0/address");
                InputStreamReader ir = new InputStreamReader(pp.getInputStream(), Charset.defaultCharset());
                LineNumberReader input = new LineNumberReader(ir);
                while (null != str) {
                    str = input.readLine();
                    if (str != null) {
                        macSerial = str.trim();
                        break;
                    }
                }
            } catch (IOException ex) {
                LogUtil.error(TAG, "getWifiMacAddress IOException:" + ex.getMessage());
            }
        }
        if (!StrUtil.isNullOrEmpty(macSerial)) {
            macAddr = macSerial.replace(":", "");
        }
        LogUtil.debug(TAG, "getEthMacAddress Address=" + macAddr);
        return macAddr;
    }

    private String getWifiMacAddress() {
        String macSerial = null;
        String macAddr = null;
        String str = "";
        boolean wlanflag = isFileExists("/sys/class/net/wlan0/address");
        if (wlanflag == true) {
            try {
                Process pp = Runtime.getRuntime().exec("cat /sys/class/net/wlan0/address");
                InputStreamReader ir = new InputStreamReader(pp.getInputStream(), Charset.defaultCharset());
                LineNumberReader input = new LineNumberReader(ir);
                while (null != str) {
                    str = input.readLine();
                    if (str != null) {
                        macSerial = str.trim();
                        break;
                    }
                }
            } catch (IOException ex) {
                LogUtil.error(TAG, "getWifiMacAddress IOException:" + ex.getMessage());
            }
        }
        if (!StrUtil.isNullOrEmpty(macSerial)) {
            macAddr = macSerial.replace(":", "");
        }
        LogUtil.debug(TAG, "getEthMacAddress Address=" + macAddr);
        return macAddr;
    }

    private boolean isFileExists(String strFile) {
        try {
            File f = new File(strFile);
            if (!f.exists()) {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 获取随机的6位数字
     *
     * @return 随机数
     */
    private String getRandomStr() {
        Random random = new Random(10);
        int num = Math.abs(random.nextInt() % 1000000) + 100000;
        LogUtil.info(TAG, "getRandomStr str=" + num);
        return String.valueOf(num);
    }

    /**
     * 密钥验证(sn=md5( random +appId +md5(合作厂商私钥)))
     *
     * @return 密钥
     */
    private String getSecretStr() {
        String randomStr = getRandomStr();
        String appId = AuthControl.getInstance().getAppId();
        String appKey = AuthControl.getInstance().getAppKey();
        String appKeyMd5 = MD5Util.getMD5String(appKey).toLowerCase(Locale.getDefault());
        String sn = MD5Util.getMD5String(randomStr + appId + appKeyMd5).toLowerCase(Locale.getDefault());
        LogUtil.info(TAG, "getSecretStr sn=" + sn);
        return sn;
    }

    /**
     * 线程执行过程
     */
    public void run() {

        while (true) {
            try {
                synchronized (objectWait) {
                    if (bWait == true) {
                        LogUtil.trace(TAG, "run to wait...");
                        objectWait.wait();
                        LogUtil.trace(TAG, "run out wait");
                    }
                }
                AuthControl.getInstance().setAuthStatus(AuthControl.AUTH_NONE);
                if (dvbAdapter.getDVBDeviceManager().getDVBDevice().isConnected()) {
                    bAuthOk = doAuth();
                    if (bAuthOk == true) {
                        AuthControl.getInstance().setApik(apik);
                        AuthControl.getInstance().setAuthStatus(AuthControl.AUTH_OK);
                        LogUtil.trace(TAG, "run AUTH_OK");
                        bWait = true;
                    } else if (bAuthOk == false && AuthControl.getInstance().getAuthStatus() == AuthControl.AUTH_FAIL) {
                        bWait = true; // 等待下次进行鉴权
                    } else {
                        bWait = false;
                        Thread.sleep(1000);
                    }
                } else {
                    bWait = false;
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                LogUtil.error(TAG, "run InterruptedException");
            } catch (Exception e) {
                LogUtil.error(TAG, "run Exception");
            }
        }
    }
}
